package com.example.demo.Interceptor;

import com.example.demo.utils.ReqDedupHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//      //返回作了请求的用户名，这个信息用来作HTTP用户论证。如果在请求中没有用户名信息，这个方法返回空值。
        String userId= request.getRemoteUser();
//
        String method = request.getRequestURI()    ;//接口名
//
//        String req = "{\n" +
//                "\"requestTime\" :\"20190101120002\",\n" +
//                "\"requestValue\" :\"1000\",\n" +
//                "\"requestKey\" :\"key\"\n" +
//                "}";
//        System.out.println(request.getParameterMap());

        String dedupMD5 = new ReqDedupHelper().dedupParamMD5(request,"requestTime");//计算请求参数摘要，其中剔除里面请求时间的干扰

        String KEY = "dedup:U=" + userId + "M=" + method + "P=" + dedupMD5;

        long expireTime =  1000;// 1000毫秒过期，1000ms内的重复请求会认为重复
        long expireAt = System.currentTimeMillis() + expireTime;
        String val = "expireAt@" + expireAt;

// NOTE:直接SETNX不支持带过期时间，所以设置+过期不是原子操作，极端情况下可能设置了就不过期了，后面相同请求可能会误以为需要去重，所以这里使用底层API，保证SETNX+过期时间是原子操作
        Boolean firstSet = stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> connection.set(KEY.getBytes(), val.getBytes(), Expiration.milliseconds(expireTime),
                RedisStringCommands.SetOption.SET_IF_ABSENT));

        final boolean isConsiderDup;
        if (firstSet != null && firstSet) {
            isConsiderDup = false;
        } else {
            isConsiderDup = true;
        }


//        System.out.println("进入拦截器了");
//        //中间写逻辑代码，比如判断是否登录成功，失败则返回false
//        return true;

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        //
        System.out.println("controller 执行完了");
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("我获取到了一个返回的结果："+response);
        System.out.println("请求结束了");
    }
}
